from typing import List, Optional, Dict
import asyncio
import logging
from dataclasses import dataclass

from src.routing.routing_table import RoutingTable, Node
from src.database.dht_repository import DHTRepository
from src.database.database import Database
from src.log.logger import setup_logger
from src.config.settings import SAVE_DB, ROUTING_CACHE_TTL

@dataclass
class RoutingMetrics:
    """路由指标"""
    total_nodes: int = 0
    active_nodes: int = 0
    queries_count: int = 0
    successful_queries: int = 0
    failed_queries: int = 0

class RoutingMiddleware:
    """路由中间件
    
    统一管理路由表和数据库操作，提供缓存和指标统计
    """
    
    def __init__(self, node_id: bytes):
        self.logger = setup_logger("routing_middleware")
        self.routing_table = RoutingTable(node_id)
        self.repo = DHTRepository() if SAVE_DB else None
        self.metrics = RoutingMetrics()
        self._cache: Dict[str, Node] = {}
        self._cache_lock = asyncio.Lock()
        
    async def add_node(self, node: Node) -> bool:
        """添加节点
        
        Args:
            node: 要添加的节点
            
        Returns:
            bool: 是否添加成功
        """
        try:
            # 添加到路由表
            success = self.routing_table.add_node(node)
            
            if success:
                # 更新缓存
                await self._update_cache(node)
                
                # 更新指标
                self.metrics.total_nodes += 1
                if node.is_active:
                    self.metrics.active_nodes += 1
                    
                # 保存到数据库
                if self.repo:
                    self.repo.save_node(node)
                    
            return success
            
        except Exception as e:
            self.logger.error(f"添加节点失败: {e}", exc_info=True)
            self.metrics.failed_queries += 1
            return False
            
    async def remove_node(self, node: Node) -> None:
        """移除节点"""
        try:
            # 从路由表移除
            self.routing_table.remove_node(node)
            
            # 从缓存移除
            await self._remove_from_cache(node)
            
            # 更新指标
            self.metrics.total_nodes -= 1
            if node.is_active:
                self.metrics.active_nodes -= 1
                
            # 更新数据库
            if self.repo:
                self.repo.update_node_status(node, success=False)
                
        except Exception as e:
            self.logger.error(f"移除节点失败: {e}", exc_info=True)
            
    async def get_node(self, node_id: bytes = None, ip: str = None, port: int = None) -> Optional[Node]:
        """获取节点
        
        优先从缓存获取，如果缓存未命中则从路由表查找
        
        Args:
            node_id: 节点ID
            ip: 节点IP
            port: 节点端口
            
        Returns:
            Optional[Node]: 找到的节点
        """
        try:
            self.metrics.queries_count += 1
            
            # 尝试从缓存获取
            cache_key = self._get_cache_key(node_id, ip, port)
            node = await self._get_from_cache(cache_key)
            if node:
                self.metrics.successful_queries += 1
                return node
                
            # 从路由表查找
            node = self.routing_table.find_node(node_id, ip, port)
            if node:
                # 更新缓存
                await self._update_cache(node)
                self.metrics.successful_queries += 1
                return node
                
            self.metrics.failed_queries += 1
            return None
            
        except Exception as e:
            self.logger.error(f"获取节点失败: {e}", exc_info=True)
            self.metrics.failed_queries += 1
            return None
            
    async def get_closest_nodes(self, target_id: bytes, count: int) -> List[Node]:
        """获取最近的节点"""
        try:
            return self.routing_table.get_closest_nodes(target_id, count)
        except Exception as e:
            self.logger.error(f"获取最近节点失败: {e}", exc_info=True)
            return []
            
    async def update_node(self, node: Node) -> bool:
        """更新节点信息"""
        try:
            success = await self.routing_table.update_node(node)
            
            if success:
                # 更新缓存
                await self._update_cache(node)
                
                # 更新数据库
                if self.repo:
                    self.repo.update_node_status(node, success=True)
                    
            return success
            
        except Exception as e:
            self.logger.error(f"更新节点失败: {e}", exc_info=True)
            return False
            
    async def load_from_database(self) -> None:
        """从数据库加载节点"""
        if not self.repo:
            return
            
        try:
            self.routing_table.load_nodes_from_db()
        except Exception as e:
            self.logger.error(f"从数据库加载节点失败: {e}", exc_info=True)
            
    def get_metrics(self) -> RoutingMetrics:
        """获取路由指标"""
        return self.metrics
        
    async def _update_cache(self, node: Node) -> None:
        """更新缓存"""
        async with self._cache_lock:
            cache_key = self._get_cache_key(node.node_id, node.ip, node.port)
            self._cache[cache_key] = node
            
    async def _remove_from_cache(self, node: Node) -> None:
        """从缓存移除"""
        async with self._cache_lock:
            cache_key = self._get_cache_key(node.node_id, node.ip, node.port)
            self._cache.pop(cache_key, None)
            
    async def _get_from_cache(self, cache_key: str) -> Optional[Node]:
        """从缓存获取"""
        async with self._cache_lock:
            return self._cache.get(cache_key)
            
    def _get_cache_key(self, node_id: bytes = None, ip: str = None, port: int = None) -> str:
        """生成缓存键"""
        if node_id:
            return f"id:{node_id.hex()}"
        return f"ip:{ip}:{port}"
